package com.jwater.core.net;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jwater.io.netty.channel.ChannelHandlerContext;
import jwater.io.netty.channel.SimpleChannelInboundHandler;
import jwater.io.netty.handler.timeout.IdleState;
import jwater.io.netty.handler.timeout.IdleStateEvent;
/**
 * @description:
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class NettyServerHandler extends SimpleChannelInboundHandler<NodePacket> {
	private static Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);
	private volatile Map<String, ChannelHandlerContext> ctxCache = new ConcurrentHashMap<>();
	private volatile Map<String, Node> nodeCache = new ConcurrentHashMap<>();
	private NettyServer nettyServer;

	public NettyServerHandler(NettyServer nettyServer) {
		this.nettyServer = nettyServer;
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		String nodeId = NettyUtils.getId(ctx);
		ctxCache.put(nodeId, ctx);
		SimpleNode node = new SimpleNode(ctx, nodeId);
		node.setHandler(nettyServer.nodeHandler);
		node.setFileHandler(nettyServer.fileHandler);
		nodeCache.put(nodeId, node);
		node.setConnect(true);
		if (nettyServer.nodeHandler != null) {
			NetExecutorUtils.execute(() -> {
				nettyServer.nodeHandler.onConnect(node);
			});
		}
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		String nodeId = NettyUtils.getId(ctx);
		SimpleNode node = (SimpleNode) nodeCache.get(nodeId);
		if (node == null) {
			logger.warn("onDisconnect error,can not find node for:" + nodeId);
		} else {
			ctxCache.remove(nodeId);
			nodeCache.remove(nodeId);
			node.setConnect(false);
			if (nettyServer.nodeHandler != null) {
				NetExecutorUtils.execute(() -> {
					nettyServer.nodeHandler.onDisconnect(node);
				});
			}
		}
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			if (((IdleStateEvent) evt).state() == IdleState.READER_IDLE) {
				ctx.disconnect();
			}
		}
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, NodePacket packet) throws Exception {
		String nodeId = NettyUtils.getId(ctx);
		SimpleNode node = (SimpleNode) nodeCache.get(nodeId);
		if (node == null) {
			logger.warn("doHandler error,can not find node for:" + nodeId);
		} else {
			node.doHandler(packet);
		}
	}

	public void close() {
		for (ChannelHandlerContext ctx : ctxCache.values()) {
			ctx.close();
		}
		ctxCache.clear();
		nodeCache.clear();
	}
}
